﻿/*
 * Copyright (c) 2011
 * Thomas Rozanski, Geoffrey Wright, Zachary Lynn, Jesse Natalie
 * All rights reserved.
 * 
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *     * Neither the name of the team nor the
 *       names of its contributors may be used to endorse or promote products
 *       derived from this software without specific prior written permission.
 * 
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THOMAS ROZANSKI, GEOFFREY WRIGHT,
 * ZACHARY LYNN, OR JESSE NATALIE BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Input;

namespace TowerDefense
{
	/// <summary>Checks keyboard and gamepad keystates.</summary>
	public class Controller
	{
		// Current input states
		private GamePadState gamepad;
		private KeyboardState keyboard;

		// Old input states
		private GamePadState oldPad;
		private KeyboardState oldKeyboard;

		// Rumble parameters
		private double rumbleStart, rumbleDuration;

		// Movement
		private Vector2 movement;

		/// <summary>Gets a unit vector of the gamepad's left stick, or keyboards wasd</summary>
		public Vector2 Movement { get { return movement; } }

		public Controller()
		{
			// Set old states
			oldPad = GamePad.GetState(0);
			oldKeyboard = Keyboard.GetState();
		}

		/// <summary>Checks if a key or button is down.</summary>
		public bool KeyDown(Keys key, Buttons button)
		{
			if (gamepad.IsConnected)
			{
				return gamepad.IsButtonDown(button);
			}
			else
			{
				return keyboard.IsKeyDown(key);
			}
		}

		/// <summary>Checks if a key or button is up.</summary>
		public bool KeyUp(Keys key, Buttons button)
		{
			if (gamepad.IsConnected)
			{
				return gamepad.IsButtonUp(button);
			}
			else
			{
				return keyboard.IsKeyUp(key);
			}
		}

		/// <summary>Checks if a key or button has been pressed.</summary>
		public bool KeyPress(Keys key, Buttons button)
		{
			if (gamepad.IsConnected)
			{
				return (gamepad.IsButtonUp(button) && oldPad.IsButtonDown(button));
			}
			else
			{
				return (keyboard.IsKeyUp(key) && oldKeyboard.IsKeyDown(key));
			}
		}

		/// <summary>Checks if a key or button has been pressed.</summary>
		public bool KeyPress(Keys key)
		{
			return (keyboard.IsKeyUp(key) && oldKeyboard.IsKeyDown(key));
		}

		/// <summary>Shakes the controller for a given amount of time.</summary>
		/// <param name="duration">Duration in milliseconds.</param>
		/// <param name="intensity">Intensity between [0.0f, 1.0f]</param>
		public void Rumble(int duration, float intensity, GameTime gameTime)
		{
			if (gamepad.IsConnected)
			{
				rumbleStart = gameTime.TotalGameTime.TotalMilliseconds;
				rumbleDuration = duration;

				GamePad.SetVibration(PlayerIndex.One, intensity, intensity);
			}
		}

		public void Update(GameTime gameTime)
		{
			// Using the gamepad
			if (gamepad.IsConnected)
			{
				// Turn off rumble if its over...
				if (gameTime.TotalGameTime.TotalMilliseconds - rumbleStart > rumbleDuration)
				{
					GamePad.SetVibration(PlayerIndex.One, 0.0f, 0.0f);
				}

				// Set up states
				oldPad = gamepad;
				gamepad = GamePad.GetState(0);

				// Compute movement
				movement = gamepad.ThumbSticks.Left;
			}
			// Using the keyboard
			else
			{
				// Set up states
				oldKeyboard = keyboard;
				keyboard = Keyboard.GetState();

				// Compute movement
				movement = Vector2.Zero;

				if (keyboard.IsKeyDown(Keys.D))
				{
					movement.X = 1.0f;
				}
				if (keyboard.IsKeyDown(Keys.A))
				{
					movement.X = -1.0f;
				}
				if (keyboard.IsKeyDown(Keys.S))
				{
					movement.Y = 1.0f;
				}
				if (keyboard.IsKeyDown(Keys.W))
				{
					movement.Y = -1.0f;
				}

				if (movement != Vector2.Zero)
				{
					movement.Normalize();
				}
			}
		}
	}
}